www.gusucode.com > VC++ 百叶窗面板组特效源码-源码程序 > VC++ 百叶窗面板组特效源码-源码程序/code/百叶窗式面板组.txt
百叶窗式面板组 作者:风林 利用百叶窗式面板组可增大窗口的可利用面积,而且把常用工具放在窗口中比放在菜单中使用更方便,现在一些大型软件如Photoshop、Dreamweaver等都采用了这种方式。在这些软件中,百叶窗式面板组都做成了可停靠的窗口,我没有这种能力,只能做成固定位置的控件组,使用时只能用在对话框或具有CFormView的视图中,整个制作很粗糙,希望高手能加以改造。 本程序的核心思路是调整控件的位置和显示/隐藏控件,当一个面板被收起或展开时,只要把它下面的控件都隐藏或显示出来,再调整各面板控件位置,这样整个面板组就像百叶窗一样可以收放自如了。 显示/隐藏控件: CWnd *pWnd; pWnd = GetDlgItem( 控件ID号 ); pWnd->ShowWindow( nShow ); GetDlgItem()函数用于获取控件的指针; ShowWindow()函数用于显示/隐藏控件,当nShow为SW_SHOW时,显示控件,为SW_HIDE时隐藏控件。 修改控件位置: CWnd *pWnd; pWnd = GetDlgItem( 控件ID号 ); pWnd->SetWindowPos( NULL,x,y,0,0,SWP_NOZORDER | SWP_NOSIZE ); SetWindowPos()函数把控件移到窗口的(x,y)处,大小不变 这个程序的设计难点在控制控件的位置上,应该尽量采用相对位置。在这里只要抓住在各种情况下标题条的位置就可以了,标题条下的各控件位置都是相对于标题条的,当标题条位置改变时,重新计算一下控件位置就可以了。 我定义了一个数组变量CPoint m_TitlePt[3]存放三个标题条的位置,其值在收放面板时进行设定。 面板1的标题条是固定的,只要设置好初值就行了; 面板2的标题条是相对于面板1的标题条的,有两种可能: 当面版1展开时,其y坐标=标题条1.y+面板1高度,即:m_TitlePt[1].y = m_TitlePt[0].y+m_BoxHeight[0]; 当面版1收起时,其y坐标=标题条1.y+标题条1高度,即:m_TitlePt[1].y = m_TitlePt[0].y+m_TitleHeight; 面板3的标题条是相对于面板2的标题条的,也有两种可能: 当面版2展开时,其y坐标=标题条2.y+面板2高度,即:m_TitlePt[2].y = m_TitlePt[1].y+m_BoxHeight[1]; 当面版2收起时,其y坐标=标题条2.y+标题条2高度,即:m_TitlePt[2].y = m_TitlePt[1].y+m_TitleHeight; 以下就是计算面板3各部分位置的函数: void CCurtainBoxDlg::CalculateControlPos3() { m_TitlePt[2].x = m_BoxRext.left; //标题条位置(左上角坐标) if( b_Mark2 ) //面板2是展开的 m_TitlePt[2].y = m_TitlePt[1].y+m_BoxHeight[1]; else //面板2是收起的 m_TitlePt[2].y = m_TitlePt[1].y+m_TitleHeight; m_ControlPt3[0] = CPoint( m_TitlePt[2].x+5, m_TitlePt[2].y+m_TitleHeight+7 ); //控件位置 m_ControlPt3[1] = CPoint( m_TitlePt[2].x+85, m_TitlePt[2].y+m_TitleHeight+7 ); m_ControlPt3[2] = CPoint( m_TitlePt[2].x+5, m_TitlePt[2].y+m_TitleHeight+35 ); } 面板下各控件位置是经反复调节确定的。其它两个面板用类似方法计算。 计算好位置后,就可以重新定位位置了,以下为设置面板3各部分位置的函数: void CCurtainBoxDlg::SetBox3Pos() { CWnd *pWnd = GetDlgItem( IDC_TITLE3 ); pWnd->SetWindowPos( NULL, m_TitlePt[2].x, m_TitlePt[2].y, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); //调整标题栏位置 int i; for( i=0; i<BOX3_NUMBER; i++ ) { pWnd = GetDlgItem( m_Box3ID[i] ); pWnd->SetWindowPos( NULL, m_ControlPt3[i].x, m_ControlPt3[i].y, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); //调整控件位置 } } 其中,BOX3_NUMBER为面板3中控件数,m_Box3ID[]存放控件ID号的数组,其值在初始化时已设置。 解决了控件位置后,就该考虑单击标题条后的调整问题了。 由于标题条是一种自绘的按钮(详见《自己动手做按钮》一文),可直接用ClassWizard添加它们的响应函数,这里我用了三个BOOL变量监视标题条状态: BOOL b_Mark1; //面板1状态:true-展开、false-收缩 BOOL b_Mark2; //面板2状态 BOOL b_Mark3; //面板3状态 当单击一个标题条时,首先修改它的状态变量,再根据新状态,计算和设置各控件位置,再重绘整个控件组就行了。还有一个问题,为了节省空间,我只允许同时展开两个面板,所以当展开一个面板时,若其它两个面板处于打开状态就应该先关闭一个。 以下为单击面板3的标题条时的响应函数: void CCurtainBoxDlg::OnTitle3() { if( m_Title3.ClickBut() ) { b_Mark3 = !b_Mark3; if( b_Mark1 && b_Mark2 && b_Mark3 ) { b_Mark1 = false; m_Title1.SetButStatus(BUT_STATUS_RIGHT); ShowBox1( SW_HIDE); } if( b_Mark3 ) ShowBox3( SW_SHOW ); else ShowBox3( SW_HIDE ); InvalidateBox(); //刷新面板组 } } m_Title3.ClickBut()是自绘的标题条按钮的成员函数,用于判定单击处是否为标题条的文字部分(参见CTitleBox类); b_Mark3 = !b_Mark3为更改面板3的状态; 其下是若三个面板都是展开的,则关闭面板1; ShowBox3()为显示/隐藏面板3中各控件的函数,定义为: void CCurtainBoxDlg::ShowBox3(int nShow) { CWnd *pWnd; for( int i=0; i<BOX3_NUMBER; i++ ) { pWnd = GetDlgItem( m_Box3ID[i] ); pWnd->ShowWindow( nShow ); } } InvalidateBox()调用计算和设置控件位置函数刷新面板组: void CCurtainBoxDlg::InvalidateBox() { CalculateControlPos1();//计算面板1各控件位置 SetBox1Pos(); //重新设置面板1各控件位置 CalculateControlPos2();//计算面板2各控件位置 SetBox2Pos(); //重新设置面板2各控件位置 CalculateControlPos3();//计算面板3各控件位置 SetBox3Pos(); //重新设置面板3各控件位置 InvalidateRect( &m_BoxRext ); //重绘面板背景以消除残留印记 } 以上为百叶窗式面板组的设计思路,完整代码参见示例程序。